/*
Title:  Bus Activity Monitor
Author: ChinniKrishna Kothapalli
Version: 0.1
Created for: ECE510: System Verilog Final Project
Description: A 6 state FSM which monoitors the output of 8086 processor
*/
module Bam(	//Inputs
		BusInterface.BamInputPort Bus,
		//Outputs
		BAMToUARTInterface.BAMToUART BTUBus);
//Timing
timeunit 1ns;
timeprecision 1ns;
//Imports
import BamPackage::*;
//State Declaration
MonitorState State,NextState;
//Internal Memory
reg [19:0] Address;
reg [15:0] Data;
reg IOM,RD,WR,Done;
integer Count;
integer Init=-1;
//Files
integer debugfile,UartFile;
//String to store the transmit data
string UartTemp;

//Reset and State Update Logic
always @(posedge Bus.Clock)
begin
	if(Bus.Reset)
		State<=IdleState;
	else
		State<=NextState;
end
//Next State Generation Logic
always_comb
begin
	NextState=State;					//Default Value
	case(State)
		IdleState:					//In Idle State
		begin			
			if(Bus.ALE)				//If ALE is high
			begin
				NextState=T1State;		//Goto T1State
				Count=Init;
			end
			else
				NextState=IdleState;		//Else Remain there
		end
		T1State:						
		begin
			if(High)
				NextState=T2State;
		end
		T2State:
		begin
			if(High)
				NextState=T3State;
		end
		T3State:
		begin
			Count=Count+1;
			if(Bus.Ready)				//If Data is Ready 
				NextState=T4State;		//Goto T4State
			else if(!Bus.Ready)			//Else Goto Wait state
				NextState=WaitState;
	
		end
		WaitState:
		begin
			Count=Count+1;	
			if(Bus.Ready)
				NextState=T4State;
			else if(!Bus.Ready)
				NextState=T3State;		
		end
		T4State:
		begin
			if(High)
				NextState=IdleState;
			else
				NextState=T4State;				
		end
	endcase
end
//Moore Machine Output depends only on State
always @(State)
begin	
	case(State)
		IdleState:
		begin
			Done<=Low;	
		end
		T1State:
		begin
			Address<={Bus.AddrStatus,Bus.AddrData};		//Latch the address
		end
		T2State:
		begin
			IOM<=Bus.IOM;					//Store the IOM
		end
		T3State:
		begin
			Data<=Bus.AddrData;				//Store the Data
		end
		WaitState:
		begin
			RD<=Bus.RD;
			WR<=Bus.WR;			
		end
		T4State:
		begin
			Data<=Bus.AddrData;			
			Done<=High;
		end		
	endcase
end
//Writing to UART
always @(posedge Done)
begin
	//Init the UART
	UartLBTransactionTest(8'h8B,High);	//Setting the UART to communicate at 115200bps
	if(IOM==High)				
	begin
		if(RD==Low)
			UartTemp="MEMR";				
		if(WR==Low)
			UartTemp="MEMW";
	end
	else if(IOM==Low)
	begin
		if(RD==Low)
			UartTemp="IOR";
		if(WR==Low)
			UartTemp="IOW";
	end
	foreach (UartTemp[i])
	begin				
		UartLBTransactionTest(UartTemp[i],Low);
	end
		
	
end
//Writing to a file
initial
begin
	debugfile=$fopen("Output.txt","w");
	UartFile=$fopen("UartOutput.txt","w");
	$fdisplay(debugfile,"RST");	
end
always @(posedge Done)
begin	
	if(IOM==High)
	begin
		if(RD==Low)
			$fdisplay(debugfile,"MEMR %h %h %d",Address,Data,Count);
		if(WR==Low)
			$fdisplay(debugfile,"MEMW %h %h %d",Address,Data,Count);
	end
	else if(IOM==Low)
	begin
		if(RD==Low)
			$fdisplay(debugfile,"IOR %h %h %d",Address,Data,Count);
		if(WR==Low)
			$fdisplay(debugfile,"IOW %h %h %d",Address,Data,Count);		
	end	
end
//Task to transmit bytes to UART
task automatic UartLBTransactionTest(input bit [7:0] DataToTransmit, input bit ControlOrData); 
	bit [7:0] RecievedData;
	fork
	    begin
	      BTUBus.TransmitData = DataToTransmit;             // Make transmit transaction
	      BTUBus.ControlOrData = ControlOrData;
	      BTUBus.TransmitDataSent = 1'b1;
	      @(posedge BTUBus.TransmitAcknowledge);
	      BTUBus.TransmitDataSent = 1'b0;
	    end
	    begin
	      if(ControlOrData==0)                              // Make recieve transaction
		begin
		  wait(BTUBus.RecieveDataSent);
		  begin
		  RecievedData = BTUBus.RecieveData;
		  BTUBus.RecieveAcknowledge = 1'b1;
		  #1;BTUBus.RecieveAcknowledge = 1'b0;
		  end
		end
	    end
	join
	$fdisplay(UartFile,"%s",RecievedData);
endtask

endmodule
